/*
 *  Copyright 2008 The MITRE Corporation (http://www.mitre.org/). All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.mitre.lattice.eav;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.mitre.lattice.query.LatticeQuery;
import org.mitre.mrald.util.MiscUtils;
import org.mitre.mrald.util.MraldConnection;
import org.mitre.mrald.util.MraldException;
import org.mitre.mrald.util.User;

/**
 *@author     Gail Hamilton
 *@created
 *@version    1.0
 *@see        java.lang.Object
 */
public abstract class EavElement
{
    /**
     *  Description of the Field
     */
    private String QUERY_INIT = "";
    private String query = "";
    private String elementType = "";
    private MraldConnection conn = null;
    private ResultSet rs = null;
    private int colCount = 0;

    private boolean printVert = false;

    /**
     *  Description of the Field
     */
    protected String whereAnd = "";
    private String colName = "";//This is the PkColName that the value of will be used to generate sql in child query
    private String colValue = "";//This is the  value of will be used to generate where clause for sql in child query

    private String displayColumn = "";

    /**
     *  Description of the Field
     */
    protected boolean hasDiv = false;
    /**
     *  Description of the Field
     */
    protected boolean endReached = false;
    /**
     *  Description of the Field
     */
    protected String endSection = "";

    /**
     *  Description of the Field
     */
    protected String sortBy;

    /**
     *  Description of the Field
     */
    protected boolean isTable = true;

    private User user;
    //if this is set then only this column will be displayed, not all data.

    /**
     *  Constructor for the QueryElements object
     *
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public EavElement()
        throws MraldException
    {
        super();
        elementType = "EAV";
        whereAnd = " WHERE ";
        init();
    }


    /**
     *  Constructor for the QueryElements object
     *
     *@param  elementType         Description of the Parameter
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public EavElement( String elementType )
        throws MraldException
    {
        super();
        this.elementType = elementType;
        whereAnd = " WHERE ";
        init();
    }


    /**
     *  Constructor for the QueryElements object
     *
     *@param  elementType         Description of the Parameter
     *@param  conn                Description of the Parameter
     *@exception  MraldException  Description of the Exception
     *@since
     */
    public EavElement( String elementType, MraldConnection conn )
        throws MraldException
    {
        super();
        this.conn = conn;
        this.elementType = elementType;
        whereAnd = " WHERE ";
        init();
    }


    /**
     *  This function, runs the query and returns the format on a line, by line
     *  case
     *
     *@exception  MraldException  Description of the Exception
     */
    public void runQuery()
        throws MraldException
    {

        rs = runQuery( query );

    }


    /**
     *  This function, runs the query and returns the format on a line, by line
     *  case
     *
     *@param  thisConn  The new connection value
     */
    public void setConnection( MraldConnection thisConn )
    {
        conn = thisConn;
    }


    /**
     *  This function, runs the query and returns the format on a line, by line
     *  case
     *
     *@return    The HTML for inclusion in the second form building page.
     */
    public MraldConnection getConnection()
    {
        return conn;
    }


    /**
     *  This function, runs the query and returns the format on a line, by line
     *  case
     *
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    public String selectHtml()
        throws MraldException
    {
        StringBuffer ret = new StringBuffer();

        try
        {
            /*
             *  prebuild the drop down lists
             *  they'll be modified later for the specific drop downs
             */
            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavElement: selectHtml: query is :"  + query);

            rs = runQuery( query );
            //if the column count isn't set default to the number in the query
            if ( colCount < 1 )
            {
                ResultSetMetaData rsmd = rs.getMetaData();
                colCount = rsmd.getColumnCount();
            }
            int i = 0;
            while ( rs.next() )
            {
                i++;

                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavElement: selectHtml  :in while loop : "  + i);
                ret.append( outputRow( colCount ) );

                ret.append( endOutputRow() );
                //Only do on the first time through
                if ( i == 1 )
                {
                    setColValue( rs.getString( colName ) );
                }

            }

            //rs.close();
            //rs = null;
            return ret.toString();
        }
        catch ( SQLException s )
        {
            throw new MraldException( "Query " + query + "produced the following exception: " + s.getMessage() );
        }

    }


    /**
     *  Gets the user attribute of the EavElement object
     *
     *@return    The user value
     */
    protected User getUser()
    {
        return user;
    }


    /**
     *  Sets the user attribute of the EavElement object
     *
     *@param  user                The new user value
     *@exception  MraldException  Description of the Exception
     */
    public void setUser( User user )
        throws MraldException
    {
        this.user = user;

        setQuery( appendToQuery( this.query, user ) );

    }


    /**
     *  This function, runs the query and returns the format on a line, by line
     *  case THis allows for lines to be 'interupted' so that sql in a different
     *  table can be displayed
     *
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    public String selectHtmlSingle()
        throws MraldException
    {
        StringBuffer ret = new StringBuffer();

        try
        {
            /*
             *  Get only one line. This means that there will
             *  be subselects based on this value
             */
            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavLIstTag: SingleHtml " + query);

            if ( rs == null )
            {
                rs = runQuery( query );
                colCount = 1;
            }

            if ( endReached )
            {
                rs = runQuery( query );
                colCount = 1;
            }
            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavLIstTag: SingleHtml :ResultSet : " + rs.toString());

            if ( rs.next() )
            {
                ret.append( outputRow( colCount ) );
                endReached = false;
            }
            else
            {
                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavLIstTag: SingleHtml " + query + "about to return null");

                endReached = true;
                return null;
            }
            setColValue( rs.getString( colName ) );
            return ret.toString();
        }
        catch ( SQLException s )
        {
            throw new MraldException( "Query " + query + "produced the following exception: " + s.getMessage() );
        }

    }


    /**
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    protected String endHtmlSingle()
        throws MraldException
    {
        return endSection;
    }


    /**
     *@exception  MraldException  Description of the Exception
     */
    protected abstract void init()
        throws MraldException;


    /**
     *@param  query               Description of the Parameter
     *@param  user                Description of the Parameter
     *@return                     Description of the Return Value
     *@exception  MraldException  Description of the Exception
     */
    protected final String appendToQuery( String query, User user )
        throws MraldException
    {
        String newQuery = LatticeQuery.adaptQuery( query, user );
        return newQuery;
    }


    /**
     *@param  colCount            Description of the Parameter
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    protected abstract StringBuffer outputRow( int colCount )
        throws MraldException;


    /**
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    protected StringBuffer endOutputRow()
        throws MraldException
    {
        return new StringBuffer();
    }


    /**
     *@param  htmlquery           Description of the Parameter
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    public ResultSet runQuery( String htmlquery )
        throws MraldException
    {
        try
        {
            if ( conn == null )
            {
            	// PM: Note that this constructor is deprecated.
                conn = new MraldConnection();
            }
            rs = conn.executeQuery( htmlquery );
            return rs;
        }
        catch ( SQLException s )
        {
            throw new MraldException( "Query failed:  " + htmlquery, s );
        }
    }


    /**
     *@return                     The HTML for inclusion in the second form
     *      building page.
     *@exception  MraldException  Description of the Exception
     */
    public String insertHtml()
        throws MraldException
    {
        /*
         *  prebuild the drop down lists
         *  they'll be modified later for the specific drop downs
         */
        StringBuffer ret = new StringBuffer();

        return ret.toString();
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    public String deleteHtml()
    {
        /*
         *  prebuild the drop down lists
         *  they'll be modified later for the specific drop downs
         */
        StringBuffer ret = new StringBuffer();

        return ret.toString();
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    public String updateHtml()
    {
        /*
         *  prebuild the drop down lists
         *  they'll be modified later for the specific drop downs
         */
        StringBuffer ret = new StringBuffer();

        return ret.toString();
    }


    /**
     *@param  initQuery  The new initQuery value
     */
    public void setInitQuery( String initQuery )
    {
        this.QUERY_INIT = initQuery;
        query = initQuery;
    }


    /**
     *@param  query  The new query value
     */
    public void setQuery( String query )
    {
        this.query = query;
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    public String getQuery()
    {
        return this.query;
    }


    /**
     *@return        The div value
     */
    public boolean getDiv()
    {
        return hasDiv;
    }


    /**
     *@param  thisColName  The new colName value
     */
    public void setColName( String thisColName )
    {
        this.colName = thisColName;
    }


    /**
     *@param  thisSortBy  The new sortBy value
     */
    public void setSortBy( String thisSortBy )
    {
        this.sortBy = thisSortBy;
    }


    /**
     *@return        The sortBy value
     */
    public String getSortBy()
    {
        return this.sortBy;
    }


    /**
     *@return        The colName value
     */
    public String getColName()
    {
        return this.colName;
    }



    /**
     *@param  colValue  The new colValue value
     */
    public void setColValue( String colValue )
    {
        this.colValue = colValue;
    }


    /**
     *@return        The colValue value
     */
    public String getColValue()
    {
        return this.colValue;
    }


    /**
     *@param  thisColumn  The new displayColumn value
     */
    public void setDisplayColumn( String thisColumn )
    {
        this.displayColumn = thisColumn;
    }


    /**
     *@return        The displayColumn value
     */
    public String getDisplayColumn()
    {
        return this.displayColumn;
    }


    /**
     *@param  printVert  The new printVert value
     */
    public void setPrintVert( boolean printVert )
    {
        this.printVert = printVert;
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    public boolean getPrintVert()
    {
        return this.printVert;
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    int getColCount()
    {
        return this.colCount;
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    String getType()
    {
        return this.elementType;
    }


    /**
     *@param  thisCount  The new colCount value
     */
    void setColCount( int thisCount )
    {
        this.colCount = thisCount;
    }


    /**
     *@return    The HTML for inclusion in the second form building page.
     */
    protected ResultSet getRs()
    {
        return rs;
    }


    /**
     *@exception  MraldException  Description of the Exception
     */
    public void close()
        throws MraldException
    {
        try
        {
            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavListTag: close. ABout to close query  "+ query  );

            if ( rs != null )
            {
                rs.close();
                rs = null;
            }
            if ( conn != null )
            {
                conn.close();
                conn = null;
            }
        }
        catch ( SQLException s )
        {
            throw new MraldException( s );
        }
    }


    /**
     *@param  columnName  The new params value
     *@param  value       The new params value
     */
    public void setParams( String columnName, String value )
    {
        if ( QUERY_INIT.toUpperCase().indexOf( " WHERE " ) > 0 )
        {
            whereAnd = " AND ";
        }
        else
        {
            whereAnd = " WHERE ";
        }
        value = MiscUtils.checkApostrophe( value );
        query = QUERY_INIT + whereAnd + columnName + " = '" + value + "'";

    }


    /**
     *@param  tableName   The new params value
     *@param  columnName  The new params value
     *@param  value       The new params value
     */
    public void setParams( String tableName, String columnName, String value )
    {
        if ( QUERY_INIT.toUpperCase().indexOf( " WHERE " ) > 0 )
        {
            whereAnd = " AND ";
        }
        else
        {
            whereAnd = " WHERE ";
        }
        value = MiscUtils.checkApostrophe( value );

        query = QUERY_INIT + whereAnd + tableName + "." + columnName + " = '" + value + "'";

    }


    /**
     *@param  columnName  The feature to be added to the Sort attribute
     */
    public void addSort( String columnName )
    {
        //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "EavElement. AddSort " + this.toString() + " Sort By: "+ columnName);

        sortBy = columnName;
        //if (query.indexOf("ORDER BY") > 0 )
        query = query + " ORDER BY " + columnName;
        //else
        //	query = query + "," + columnName;

    }


    /**
     *@param  columnName  The feature to be added to the Params attribute
     *@param  value       The feature to be added to the Params attribute
     */
    public void addParams( String columnName, String value )
    {
        if ( query.indexOf( whereAnd ) > 0 )
        {
            whereAnd = " AND ";
        }
        else
        {
            whereAnd = " WHERE ";
        }
        value = MiscUtils.checkApostrophe( value );

        query = query + whereAnd + columnName + " = '" + value + "'";

    }


    /**
     *@param  tableName   The feature to be added to the Params attribute
     *@param  columnName  The feature to be added to the Params attribute
     *@param  value       The feature to be added to the Params attribute
     */
    public void addParams( String tableName, String columnName, String value )
    {
        if ( query.indexOf( whereAnd ) > 0 )
        {
            whereAnd = " AND ";
        }
        else
        {
            whereAnd = " WHERE ";
        }
        value = MiscUtils.checkApostrophe( value );

        query = query + whereAnd + tableName + "." + columnName + " = '" + value + "'";

    }


    /**
     *  Sets the isTable attribute of the EavElement object
     *
     *@param  setIsTable  The new isTable value
     */
    public void setIsTable( boolean setIsTable )
    {
        isTable = setIsTable;
    }


    /**
     *  Gets the isTable attribute of the EavElement object
     *
     *@return    The isTable value
     */
    public boolean getIsTable()
    {
        return isTable;
    }


    /**
     *@exception  Throwable  Description of the Exception
     */
    public void finalize()
        throws Throwable
    {
        close();
    }
}

